<?php
namespace Waybill;

//错误信息
const statusSuccess = 0;

class Wlhy
{
  private string $baseurl; // url
  private string $account; // 账号
  private string $passwd; // 密码：sha1加密
  private array $token; // token

  /**
   * 构造函数
   */
  public function __construct($config = []){
    $this->baseurl = $config["baseurl"] ?? "";
    $this->account = $config["account"] ?? "";
    $this->passwd = $config["passwd"] ?? "";
    $this->token = $config["token"]??[];
  }

  /**
   * 数据响应
   * @param $res
   * @return array
   */
  private function response($code = 1, $msg = "操作成功", $data = []){
    return [
      "code" => $code,
      "msg" => $msg,
      "data" => $data
    ];
  }

  /**
   * 获取curl响应头
   * @param $curl
   * @param $headerLine
   * @return int
   */
  private function headerHandler($curl, $headerLine):int
  {
    $len = strlen($headerLine);
    // HTTP响应头是以:分隔key和value的
    $split = explode(':', $headerLine, 2);
    if (count($split) > 1) {
      $key = trim($split[0]);
      $value = trim($split[1]);
      // 将响应头的key和value存放在全局变量里
      $GLOBALS['G_HEADER'][$key] = $value;
    }
    return $len;
  }

  /**
   * 处理curl
   * @param $url // url地址
   * @param $type // GET、POST、PUT、DELETE、PATCH
   * @param $data // 发送数据
   * @return mixed
   */
  private function dealCurl($url, $type, $data, $header = []):array
  {
    //设置heder头，如果头部没有Content-Type则默认：content-type: application/json
    $existsContentType = false;
    foreach ($header as $v) {
      if (preg_match('/^(content-type)/', strtolower($v))) {
        $existsContentType = true;
        break;
      }
    }
    if (!$existsContentType) {
      array_unshift($header, 'Content-Type:application/json');
      $data = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    //初始化curl
    $handle = curl_init();
    curl_setopt_array(
      $handle, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => false, //对认证证书来源的检查 https请求 不验证证书和hosts
        CURLOPT_SSL_VERIFYHOST => false,  //从证书中检查SSL加密算法是否存在
        CURLOPT_TIMEOUT => 60,
        CURLINFO_HEADER_OUT => 1,
        CURLOPT_HEADERFUNCTION => [self::class, "headerHandler"], // 设置header处理函数
        CURLOPT_CUSTOMREQUEST => $type,
        CURLOPT_HTTPHEADER => $header,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5
      ]
    );

    //执行
    $result = curl_exec($handle);
    if (curl_errno($handle)) {
      return [
        "errCode" => 10000,
        "errMsg" => "发生错误：" . curl_error($handle),
        "result" => $result,
        "header" => $GLOBALS['G_HEADER']
      ];
    }

    //关闭
    curl_close($handle);

    //返回
    $result = is_string($result) && (is_object(json_decode($result)) || is_array(json_decode($result, true))) ? json_decode($result, true) : $result;
    return [
      "errCode" => 0,
      "errMsg" => "操作成功",
      "result" => $result,
      "header" => $GLOBALS['G_HEADER']
    ];
  }

  /**
   * 获取公钥
   * @return array
   */
  public function getPubKey():array
  {
    //获取token
    $url = $this->baseurl . "/wlhy-user/RsaController/getPubKey";
    $res = $this->dealCurl($url, "POST", []);

    //验证
    if ($res["errCode"] != 0 || !isset($res["result"]["code"]) || $res["result"]["code"] != statusSuccess) {
      //返回错误
      return $this->response(0,"错误：" . $res["result"]["code"] . "[" . $res["result"]["message"] . "]");
    }
    return $this->response(1,"操作成功", ["result" => $res["result"]["data"]]);
  }

  /**
   * 获取token：有效期2h
   * @return array
   */
  public function getToken($publicKey = ""):array
  {
    //请求数据
    $data = [
      "account" => $this->account, // 账号
      "passwd" => $this->passwd, // 用户账号所对应的加密后的密码
      "publicRsa" => $publicKey, // 加密密码的公钥，从获取公钥接口获取
      "systemCode" => "debugSystem"  // 登录类型debugSystem为调测接入令牌申请，不填为正式环境令牌申请
    ];
    p($data);

    //获取token
    $url = $this->baseurl . "/wlhy-user/user/exgLogin";
    $res = $this->dealCurl($url, "POST", $data);

    //验证
    if ($res["errCode"] != 0 || !isset($res["result"]["code"]) || $res["result"]["code"] != statusSuccess) {
      //返回错误
      return $this->response(0,"错误：" . $res["result"]["code"] . "[" . $res["result"]["message"] . "]", ["result" => $res["result"]]);
    }
    return $this->response(1,"操作成功", ["result" => $res["result"]["data"]]);
  }

  /**
   * 集合接口
   * @param $type 类型
   * @param $reqData 请求数据
   * @return array
   */
  public function dealReport($type = "", $reqData = []):array
  {
    //验证
    if(empty($reqData)){
      return $this->response(0,"参数缺失");
    }

    //类型、接口url
    $typeArrUrl = [
      "uploadFile" => $this->baseurl . "/file/uploadImage", // 文件上传接口：上传电子运单、车辆信息、驾驶员信息中相关图片文件(备注:文件大小需要小于2M)
      "transport" => $this->baseurl . "/api/v1/transport", // 电子运单上报接口：批量或者单个电子运单数据上报接口，上报电子运单数据前，必须先上报通过校验的车辆数据和驾驶员数据
      "money" => $this->baseurl . "/api/v1/money", // 资金流水单上报接口：批量或者单个资金流水单数据上报接口
      "vehicle" => $this->baseurl . "/api/v1/vehicle", // 车辆基本信息上报接口：批量或者单个车辆基本信息数据上报接口
      "driver" => $this->baseurl . "/api/v1/driver", // 驾驶员基本信息上报接口：批量或者单个驾驶员基本信息数据上报接口
      "transportValidate" => $this->baseurl . "/api/v1/transport/validate", // 运单校验结果查询接口：批量或者单个驾驶员基本信息数据上报接口
      "vehicleValidate" => $this->baseurl . "/api/v1/vehicle/validate", // 车辆信息校验结果查询接口：批量或者单个驾驶员基本信息数据上报接口
      "driverValidate" => $this->baseurl . "/api/v1/driver/validate", // 驾驶员信息校验结果查询接口：批量或者单个驾驶员基本信息数据上报接口
      "transportAppeal" => $this->baseurl . "/api/transport/appeal", // 运单申诉接口：异常运单申诉
      "transportAppealQuery" => $this->baseurl . "/api/transport/appeal/query" // 运单申诉结果查询接口
    ];
    $typeArr = array_keys($typeArrUrl);
    if(!in_array($type, $typeArr)){
      return $this->response(0,"接口不存在");
    }

    //头部信息
    $header = [
      "token:" . $this->token["token"],
      "userId:" . $this->token["user"]["id"]
    ];

    //处理数据
    switch ($type){
      case "uploadFile":
        //验证
        if(empty($reqData["file"]) || !file_exists($reqData["file"])){
          return $this->response(0,"文件缺失");
        }

        //文件大小需要小于2M
        if(filesize($reqData["file"]) > 2*1024*1024){
          return $this->response(0,"文件大小需小于2M");
        }

        //请求数据
        //文件
        $fileName = urlencode(basename($reqData["file"]));
        $fileContent = file_get_contents($reqData["file"]); // 文件内容

        //设置请求body信息
        $boundary = md5(uniqid()); // 边界符，可以随机生成
        $limiter = "\r\n";
        $limiterLine = "--";
        $bodyData = $limiterLine . $boundary . $limiter;
        $bodyData .= "Content-Type:application/octet-stream" . $limiter;
        $bodyData .= "Content-Disposition:form-data; name=\"image\"; filename=\"{$fileName}\"" . $limiter;
        $bodyData .= $limiter . $fileContent . $limiter;
        $bodyData .= $limiterLine . $boundary . $limiterLine;

        //头部信息
        $header = [
          "Content-Type:multipart/form-data; boundary=" . $boundary . "; charset=utf-8", // form-data 的 boundary 头部
          "token:" . $this->token["token"],
          "userId:" . $this->token["user"]["id"]
        ];
        $reqData = $bodyData;
        break;
      default:
        break;
    }

    //请求
    $url = $typeArrUrl[$type];
    $res = $this->dealCurl($url, "POST", $reqData, $header);
    if ($res["errCode"] != 0 || !isset($res["result"]["status"]) || $res["result"]["status"] != statusSuccess) {
      //返回错误
      return $this->response(0,"错误：" . $res["result"]["status"] . "[" . $res["result"]["message"] . "]");
    }
    return $this->response(1,"操作成功", ["result" => $res["result"]["result"]]);
  }
}